/*
 * Copyright (C) 2025 Tsingteng MicroSystem
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/**
 * @file rw_t3t.c
 * @brief T3T tag implementation
 */

#include "nci_feature.h"
#if IS_FEATURE_ON(NCI_FEATURE_RW_T3T)

#include "nfa_rw.h"
#include "rw_tag.h"
#include "nci_rf.h"
#include "discover_int.h"
#include "rw_int.h"

#define T3T_CMD_CHECK 0x06
#define T3T_CMD_UPDATE 0x08

#define T3T_RSP_CHECK 0x07
#define T3T_RSP_UPDATE 0x09


#define T3T_CMD_OFFSET_SOD 0
#define T3T_CMD_OFFSET_CMD 1
#define T3T_CMD_OFFSET_UID 2

#define T3T_RSP_OFFSET_SOD 0
#define T3T_RSP_OFFSET_CMD 1
#define T3T_RSP_OFFSET_UID 2
#define T3T_RSP_OFFSET_STATUS1 10
#define T3T_RSP_OFFSET_STATUS2 11
#define T3T_RSP_OFFSET_BLCOK_DATA 13

#define T3T_SENSF_RES_PMM_OFFSET 8
#define T3T_SENSF_RES_RD_OFFSET 16
#define T3T_SENSF_RES_RD_LEN 2

#define T3T_STATUS_FLAG_SUCCESS 0x00

#define T3T_POLL_RC_NO_SC 0
#define T3T_POLL_RC_SC    1

#define T3T_MASK_TWO_BYTE_BLOCK_FORMAT 0x80
#define T3T_MASK_THREE_BYTE_BLOCK_FORMAT 0x00

#define T3T_SYSTEM_CODE_CHECK_PRESENCE 0xFFFF
#define T3T_SYSTEM_CODE_NDEF 0x12FC
#define T3T_SYSTEM_CODE_FELICA_LITE 0x88B4
#define T3T_TSN_CHECK_PRESENCE 0x03

#define T3T_SERVICE_CODE_NDEF_RO 0x000B
#define T3T_SERVICE_CODE_NDEF_RW 0x0009

#define T3T_BLOCK_ID_FELICALITE_MC 0x88

#define T3T_UID_LEN 8
#define T3T_BLOCK_SIZE 16

#define T3T_NDEF_ATTR_OFFSET_VER 0
#define T3T_NDEF_ATTR_OFFSET_NBR 1
#define T3T_NDEF_ATTR_OFFSET_NBW 2
#define T3T_NDEF_ATTR_OFFSET_N_MAX_B 3
#define T3T_NDEF_ATTR_OFFSET_WRITE_FLAG 9
#define T3T_NDEF_ATTR_OFFSET_RW_FLAG 10
#define T3T_NDEF_ATTR_OFFSET_LN 11
#define T3T_NDEF_ATTR_OFFSET_CHECKSUM 14

#define T3T_FELICALITE_OFFSET_MC_SP 0
#define T3T_FELICALITE_OFFSET_SYS_OP 3
#define T3T_FELICALITE_OFFSET_RF_PRM 4

#define T3T_NDEF_WRITE_OFF 0x00
#define T3T_NDEF_WRITE_ON 0x0F
#define T3T_NDEF_READ_ONLY 0x00
#define T3T_NDEF_READ_WRITE 0x01

#define T3T_NDEF_VERSION 0x10
#define T3T_DEFAULT_FELICALITE_NBR 4
#define T3T_DEFAULT_FELICALITE_NBW 1
#define T3T_DEFAULT_FELICALITE_NMAXB 0x000D
#define T3T_DEFAULT_FELICALITE_CHECKSUM \
    ((T3T_NDEF_VERSION + T3T_DEFAULT_FELICALITE_NBR + T3T_DEFAULT_FELICALITE_NBW + \
    (T3T_DEFAULT_FELICALITE_NMAXB >> 8) + (T3T_DEFAULT_FELICALITE_NMAXB & 0xFF) + \
    T3T_NDEF_WRITE_OFF + T3T_NDEF_READ_WRITE) & 0xFFFF)

#define T3T_DEFAULT_FELICALITE_SYS_OP 0x01
#define T3T_DEFAULT_FELICALITE_RF_PRM 0x07

#define T3T_MAX_CHECK_BLOCK_NUM 15
#define T3T_MAX_UPDATE_BLOCK_NUM 13

#define T3T_SUPPORT_NDEF_VERSION 0x10
#define T3T_GET_MAJOR_VERSION(_ver) ((_ver) >> 4)

extern bool g_dta_mode_enabled;

/** @brief T3T卡片信息 */
typedef struct {
    /** @brief 卡片UID */
    uint8_t uid[T3T_UID_LEN];
    /** @brief 当前T3T Polling选中的SystemCode */
    uint16_t curr_system_code;
    /** @brief 标识卡片是否是Felica卡片 */
    bool is_felica;
#if IS_FEATURE_ON(NCI_FEATURE_RW_NDEF)
    /** @brief 是否已经完成NDEF检测 */
    bool is_ndef_detected;
    /** @brief 当前NDEF ATTR Block数据 */
    uint8_t ndef_attr[T3T_BLOCK_SIZE];
    /** @brief NDEF版本信息 */
    uint8_t ndef_ver;
    /** @brief NDEF Service每条Check指令最多支持的同时读取的Block数量 */
    uint8_t ndef_nbr;
    /** @brief NDEF Service每条Update指令最多支持的同时写入的Block数量 */
    uint8_t ndef_nbw;
    /** @brief NDEF Service中最多可以用于存储NDEF数据的Block数量 */
    uint16_t ndef_max_block;
    /** @brief NDEF写入标志位 */
    uint8_t ndef_write_flag;
    /** @brief NDEF读写权限控制标志位 */
    uint8_t ndef_rw_flag;
    /** @brief 当前卡片中存储的NDEF数据长度 */
    uint32_t ndef_len;
#endif
} tT3T_INFO;

static tT3T_INFO s_t3t_info;

static tNCI_STATUS t3t_polling(uint16_t system_code, uint8_t rc, uint8_t tsn, bool force_send) {
    if (!force_send && system_code == s_t3t_info.curr_system_code) {
        NFCLOG_I("t3t polling curr system code is already %04X", system_code);
        return NCI_STATUS_OK;
    }
    tNCI_RF_SENSF_REQ_PARAMS sensf_req = (system_code << 16) | (rc << 8) | tsn;
    tNCI_STATUS ret = rf_t3t_polling(sensf_req, NULL, NULL);
    if (ret != NCI_STATUS_OK) {
        return ret;
    }
    s_t3t_info.curr_system_code = system_code;
    return ret;
}

#if IS_FEATURE_ON(NCI_FEATURE_RW_NDEF)

/** @brief T3T NDEF Format时使用的默认ATTR Block数据 */
static uint8_t s_t3t_default_ndef_attr[T3T_BLOCK_SIZE] = {
    T3T_NDEF_VERSION, // VER
    T3T_DEFAULT_FELICALITE_NBR, // NBR (max block reader per cmd)
    T3T_DEFAULT_FELICALITE_NBW, // NBW (max block writer per cmd)
    T3T_DEFAULT_FELICALITE_NMAXB >> 8, // NmaxB (NDEF max block size)
    T3T_DEFAULT_FELICALITE_NMAXB & 0xFF, // NmaxB (NDEF max block size)
    0, 0, 0, 0, // RFU
    T3T_NDEF_WRITE_OFF, // Write Flag
    T3T_NDEF_READ_WRITE, // RW Flag
    0, 0, 0, // LEN
    T3T_DEFAULT_FELICALITE_CHECKSUM >> 8, // Checksum
    T3T_DEFAULT_FELICALITE_CHECKSUM & 0xFF, // Checksum
};

static tNCI_STATUS t3t_send_cmd(tNCI_BUF *cmd, tNCI_BUF *rsp) {
    cmd->data[0] = cmd->len;
    tNCI_STATUS ret = rw_transmit(cmd, rsp);
    if (ret != NCI_STATUS_OK) {
        return ret;
    }
    if (rsp->data[T3T_RSP_OFFSET_SOD] != rsp->len) {
        NFCLOG_E("t3t data rsp len error, %d", rsp->data[0]);
        return NCI_STATUS_EXT_FAILED;
    }
    if (rsp->data[T3T_RSP_OFFSET_CMD] != (cmd->data[T3T_CMD_OFFSET_CMD] + 1)) {
        NFCLOG_E("t3t data rsp cmd error, 0x%02X", rsp->data[T3T_RSP_OFFSET_CMD]);
        return NCI_STATUS_EXT_FAILED;
    }
    if (memcmp(&rsp->data[T3T_RSP_OFFSET_UID], s_t3t_info.uid, T3T_UID_LEN)) {
        NFCLOG_E("t3t data rsp uid error");
        return NCI_STATUS_EXT_FAILED;
    }
    if (rsp->data[T3T_RSP_OFFSET_STATUS1] != T3T_STATUS_FLAG_SUCCESS) {
        NFCLOG_E("t3t data rsp status error, status1=0x%02X status2=%02X", rsp->data[T3T_RSP_OFFSET_STATUS1], rsp->data[T3T_RSP_OFFSET_STATUS2]);
        return NCI_STATUS_EXT_FAILED;
    }
    return ret;
}

static tNCI_STATUS t3t_check(uint16_t service_code, uint8_t num_of_block, uint16_t* blocks, tNCI_BUF **pp_rsp) {
    tNCI_BUF *cmd = alloc_nci_buf(0);
    tNCI_BUF *rsp = *pp_rsp;
    if (rsp) {
        reset_nci_buf(rsp);
    } else {
        rsp = alloc_nci_buf(0);
    }

    tNCI_STATUS ret = NCI_STATUS_EXT_FAILED;
    if (!cmd || !rsp) {
        ret = NCI_STATUS_EXT_ALLOC_FAILED;
        goto failed;
    }

    tT3T_INFO *p_t3t = &s_t3t_info;

    UINT8_TO_BUF(cmd, 0); // 为SOD预留
    UINT8_TO_BUF(cmd, T3T_CMD_CHECK);
    ARRAY_TO_BUF(cmd, p_t3t->uid, T3T_UID_LEN);
    UINT8_TO_BUF(cmd, 1);
    UINT16_TO_BUF_LE(cmd, service_code);
    UINT8_TO_BUF(cmd, num_of_block);
    for (int i = 0; i < num_of_block; ++i) {
        uint16_t block_no = blocks[i];
        if (block_no > 0xFF) {
            UINT8_TO_BUF(cmd, T3T_MASK_THREE_BYTE_BLOCK_FORMAT);
            UINT16_TO_BUF_LE(cmd, block_no);
        } else {
            UINT8_TO_BUF(cmd, T3T_MASK_TWO_BYTE_BLOCK_FORMAT);
            UINT8_TO_BUF(cmd, block_no);
        }
    }

    ret = t3t_send_cmd(cmd, rsp);
    if (ret != NCI_STATUS_OK) {
        goto failed;
    }

    uint16_t block_data_len = num_of_block * T3T_BLOCK_SIZE;

    if (rsp->len < (T3T_RSP_OFFSET_BLCOK_DATA + block_data_len)) {
        ret = NCI_STATUS_EXT_FAILED;
        NFCLOG_E("t3t data rsp len error, %d", rsp->len);
        goto failed;
    }

    *pp_rsp = rsp;
    goto cleanup;
failed:
    free_nci_buf(rsp);
    *pp_rsp = NULL;
cleanup:
    free_nci_buf(cmd);
    return ret;
}

static tNCI_STATUS t3t_update(uint16_t service_code, uint16_t block_no, uint8_t *p_dat, tNCI_BUF **pp_rsp) {
    tNCI_BUF *cmd = alloc_nci_buf(0);
    tNCI_BUF *rsp = *pp_rsp;
    if (rsp) {
        reset_nci_buf(rsp);
    } else {
        rsp = alloc_nci_buf(0);
    }
    tNCI_STATUS ret = NCI_STATUS_EXT_FAILED;
    if (!cmd || !rsp) {
        ret = NCI_STATUS_EXT_ALLOC_FAILED;
        goto failed;
    }
    UINT8_TO_BUF(cmd, 0); // 为SOD预留
    UINT8_TO_BUF(cmd, T3T_CMD_UPDATE);
    ARRAY_TO_BUF(cmd, s_t3t_info.uid, T3T_UID_LEN);
    UINT8_TO_BUF(cmd, 1);
    UINT16_TO_BUF_LE(cmd, service_code);
    UINT8_TO_BUF(cmd, 1);
    if (block_no > 0xFF) {
        UINT8_TO_BUF(cmd, T3T_MASK_THREE_BYTE_BLOCK_FORMAT);
        UINT16_TO_BUF_LE(cmd, block_no);
    } else {
        UINT8_TO_BUF(cmd, T3T_MASK_TWO_BYTE_BLOCK_FORMAT);
        UINT8_TO_BUF(cmd, block_no);
    }
    ARRAY_TO_BUF(cmd, p_dat, T3T_BLOCK_SIZE);

    ret = t3t_send_cmd(cmd, rsp);

    if (ret != NCI_STATUS_OK) {
        goto failed;
    }

    *pp_rsp = rsp;
    goto cleanup;
failed:
    free_nci_buf(rsp);
    *pp_rsp = NULL;
cleanup:
    free_nci_buf(cmd);
    return ret;
}

static uint16_t t3t_checksum(uint8_t *data, uint8_t offset, uint8_t size) {
    uint16_t sum = 0;
    for (uint8_t i = 0; i < size; i++) {
        sum += data[offset + i];
    }
    return sum;
}

static tNCI_STATUS set_ndef_info() {
    tT3T_INFO *p_t3t = &s_t3t_info;
    p_t3t->ndef_ver = p_t3t->ndef_attr[T3T_NDEF_ATTR_OFFSET_VER];
    p_t3t->ndef_nbr = p_t3t->ndef_attr[T3T_NDEF_ATTR_OFFSET_NBR];
    p_t3t->ndef_nbw = p_t3t->ndef_attr[T3T_NDEF_ATTR_OFFSET_NBW];
    p_t3t->ndef_max_block = (uint16_t) p_t3t->ndef_attr[T3T_NDEF_ATTR_OFFSET_N_MAX_B] << 8 | p_t3t->ndef_attr[T3T_NDEF_ATTR_OFFSET_N_MAX_B + 1];
    p_t3t->ndef_write_flag = p_t3t->ndef_attr[T3T_NDEF_ATTR_OFFSET_WRITE_FLAG];
    p_t3t->ndef_rw_flag = p_t3t->ndef_attr[T3T_NDEF_ATTR_OFFSET_RW_FLAG];
    p_t3t->ndef_len = (uint32_t) p_t3t->ndef_attr[T3T_NDEF_ATTR_OFFSET_LN] << 16 | p_t3t->ndef_attr[T3T_NDEF_ATTR_OFFSET_LN + 1] << 8 | p_t3t->ndef_attr[T3T_NDEF_ATTR_OFFSET_LN + 2];

    NFCLOG_I("============== T3T NDEF Info Start ==============");
    NFCLOG_I("UID: 0x%02X%02X%02X%02X%02X%02X%02X%02X", p_t3t->uid[0], p_t3t->uid[1], p_t3t->uid[2], p_t3t->uid[3], p_t3t->uid[4], p_t3t->uid[5], p_t3t->uid[6], p_t3t->uid[7]);
    NFCLOG_I("CURR_SYSTEM_CODE: 0x%04X", p_t3t->curr_system_code);
    NFCLOG_I("NDEF Version: 0x%02X", p_t3t->ndef_ver);
    NFCLOG_I("NDEF NBR: %d", p_t3t->ndef_nbr);
    NFCLOG_I("NDEF NBW: %d", p_t3t->ndef_nbw);
    NFCLOG_I("NDEF Max Block: %d", p_t3t->ndef_max_block);
    NFCLOG_I("NDEF Write Flag: 0x%02X", p_t3t->ndef_write_flag);
    NFCLOG_I("NDEF RW Flag: 0x%02X", p_t3t->ndef_rw_flag);
    NFCLOG_I("NDEF Length: %d", p_t3t->ndef_len);
    NFCLOG_I("============== T3T NDEF Info End ================");

    if (T3T_GET_MAJOR_VERSION(T3T_SUPPORT_NDEF_VERSION) < T3T_GET_MAJOR_VERSION(p_t3t->ndef_ver)) {
        NFCLOG_E("T3T NDEF Version not supported, support version=0x%02X, card version=0x%02X", T3T_SUPPORT_NDEF_VERSION, p_t3t->ndef_ver);
        return NCI_STATUS_EXT_NOT_SUPPORTED;
    }
    if (p_t3t->ndef_nbr > T3T_MAX_CHECK_BLOCK_NUM || p_t3t->ndef_nbw > T3T_MAX_UPDATE_BLOCK_NUM) {
        NFCLOG_E("T3T NDEF Block number not supported, NBR=%d, NBW=%d", p_t3t->ndef_nbr, p_t3t->ndef_nbw);
        return NCI_STATUS_EXT_NOT_SUPPORTED;
    }
    return NCI_STATUS_OK;
}

static tNCI_STATUS scan_t3t_data() {
    tT3T_INFO *p_t3t = &s_t3t_info;
    if (p_t3t->is_ndef_detected) {
        return NCI_STATUS_OK;
    }

    tNCI_STATUS ret = t3t_polling(T3T_SYSTEM_CODE_NDEF, T3T_POLL_RC_NO_SC, 0, false);
    if (ret != NCI_STATUS_OK) {
        return ret;
    }
    tNCI_BUF *rsp = NULL;
    uint16_t ndef_attr_block_no = 0;
    ret = t3t_check(T3T_SERVICE_CODE_NDEF_RO, 1, &ndef_attr_block_no, &rsp);
    if (ret != NCI_STATUS_OK) {
        goto cleanup;
    }

    if (!osi_memcpy_s(p_t3t->ndef_attr, T3T_BLOCK_SIZE, &rsp->data[T3T_RSP_OFFSET_BLCOK_DATA], T3T_BLOCK_SIZE)) {
        ret = NCI_STATUS_EXT_COPY_FAILED;
        NFCLOG_E("t3t ndef attr copy failed");
        goto cleanup;
    }
    uint16_t sum = t3t_checksum(p_t3t->ndef_attr, 0, T3T_BLOCK_SIZE - 2);
    uint16_t attr_sum = (uint16_t)p_t3t->ndef_attr[T3T_NDEF_ATTR_OFFSET_CHECKSUM] << 8 | p_t3t->ndef_attr[T3T_NDEF_ATTR_OFFSET_CHECKSUM + 1];
    if (sum != attr_sum) {
        ret = NCI_STATUS_EXT_FAILED;
        NFCLOG_E("t3t ndef attr t3t_checksum error, sum=0x%04X, attr_sum=0x%04X", sum, attr_sum);
        goto cleanup;
    }
    ret = set_ndef_info();
    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("t3t ndef set info failed, ret=0x%X", ret);
        goto cleanup;
    }
    p_t3t->is_ndef_detected = true;

cleanup:
    free_nci_buf(rsp);
    if (ret != NCI_STATUS_OK) {
        osi_memset_s(p_t3t->ndef_attr, T3T_BLOCK_SIZE, 0, T3T_BLOCK_SIZE);
    }
    return ret;
}

static tNCI_STATUS ndef_detect(tNCI_RW_NDEF_INFO *p_ndef) {
    tT3T_INFO *p_t3t = &s_t3t_info;
    p_t3t->is_ndef_detected = false;
    tNCI_STATUS ret = scan_t3t_data();
    if (ret != NCI_STATUS_OK) {
        return ret;
    }

    if (p_t3t->ndef_len == 0) {
        NFCLOG_I("empty NDEF message");
    }
    if (p_t3t->ndef_write_flag == T3T_NDEF_WRITE_ON) {
        NFCLOG_E("WriteFlag ON: NDEF data may be inconsistent, conclude NDEF Read procedure");
        return NCI_STATUS_EXT_FAILED;
    }

    p_ndef->curr_size = p_t3t->ndef_len;
    p_ndef->max_size = p_t3t->ndef_max_block * T3T_BLOCK_SIZE;
    if (p_t3t->ndef_rw_flag == T3T_NDEF_READ_WRITE) {
        p_ndef->mode = NCI_RW_NDEF_MODE_READ_WRITE;
    } else {
        p_ndef->mode = NCI_RW_NDEF_MODE_READ_ONLY;
    }

    return NCI_STATUS_OK;
}

static tNCI_STATUS ndef_read(tNCI_RSP *p_ndef_rsp) {
    tT3T_INFO *p_t3t = &s_t3t_info;
    if (!p_t3t->is_ndef_detected) {
        NFCLOG_E("NDEF not detected");
        return NCI_STATUS_EXT_FAILED;
    }
    uint32_t ndef_len = p_t3t->ndef_len;
    if (ndef_len == 0) {
        NFCLOG_I("empty NDEF message");
        return NCI_STATUS_EXT_EMPTY_DATA;
    }
    if (p_t3t->ndef_write_flag == T3T_NDEF_WRITE_ON) {
        NFCLOG_E("WriteFlag ON: NDEF data may be inconsistent, conclude NDEF Read procedure");
        return NCI_STATUS_EXT_FAILED;
    }

    tNCI_STATUS ret = t3t_polling(T3T_SYSTEM_CODE_NDEF, T3T_POLL_RC_NO_SC, 0, false);
    if (ret != NCI_STATUS_OK) {
        return ret;
    }

    tNCI_BUF *rsp = NULL;
    uint16_t *p_blocks = NULL;

    p_ndef_rsp->data = osi_calloc(ndef_len);
    if (!p_ndef_rsp->data) {
        NFCLOG_E("t3t ndef read alloc failed");
        goto cleanup;
    }

    uint8_t nbr = p_t3t->ndef_nbr;
    p_blocks = osi_calloc(sizeof(uint16_t) * nbr);
    if (!p_blocks) {
        NFCLOG_E("t3t ndef read alloc p_blocks failed");
        goto cleanup;
    }
    uint32_t block_no = 1;
    while (p_ndef_rsp->len < ndef_len) {
        // 每轮循环读取最多nbr个Block
        uint32_t remain_len = ndef_len - p_ndef_rsp->len; // 剩余NDEF数据的长度
        uint32_t remain_block = remain_len / T3T_BLOCK_SIZE; // 剩余NDEF数据的Block数量
        if (remain_len % T3T_BLOCK_SIZE) {
            ++remain_block;
        }

        uint8_t curr_nob = (remain_block > nbr) ? nbr : remain_block; // 本次读取的Block数量
        uint32_t curr_read_len = curr_nob * T3T_BLOCK_SIZE; // 本次读取的长度
        if (curr_read_len > remain_len) {
            curr_read_len = remain_len;
        }
        for (uint8_t i = 0; i < curr_nob; ++i) {
            p_blocks[i] = block_no + i;
        }

        ret = t3t_check(T3T_SERVICE_CODE_NDEF_RO, curr_nob, p_blocks, &rsp);
        if (ret != NCI_STATUS_OK) {
            NFCLOG_E("t3t ndef read failed, ret=0x%X", ret);
            goto cleanup;
        }

        if (!osi_memcpy_s(p_ndef_rsp->data + p_ndef_rsp->len, remain_len, rsp->data + T3T_RSP_OFFSET_BLCOK_DATA, curr_read_len)) {
            NFCLOG_E("t3t ndef read memcpy failed");
            goto cleanup;
        }

        p_ndef_rsp->len += curr_read_len;
        block_no += curr_nob;
    }

    if (p_ndef_rsp->len != ndef_len) {
        NFCLOG_E("t3t ndef read len error, %d/%d", p_ndef_rsp->len, ndef_len);
        ret = NCI_STATUS_EXT_FAILED;
        goto cleanup;
    }

    ret = NCI_STATUS_OK;

cleanup:
    if (ret != NCI_STATUS_OK) {
        if (p_ndef_rsp->data) {
            osi_free(p_ndef_rsp->data);
        }
        p_ndef_rsp->len = 0;
    }
    if (p_blocks) {
        osi_free(p_blocks);
    }
    free_nci_buf(rsp);
    return ret;
}

static tNCI_STATUS ndef_format() {
    tNCI_STATUS ret = t3t_polling(T3T_SYSTEM_CODE_FELICA_LITE, T3T_POLL_RC_SC, 0, false);
    if (ret != NCI_STATUS_OK) {
        return ret;
    }
    tNCI_BUF *rsp = NULL;
    tT3T_INFO *p_t3t = &s_t3t_info;
    uint16_t mc_block = T3T_BLOCK_ID_FELICALITE_MC;
    ret = t3t_check(T3T_SERVICE_CODE_NDEF_RO, 1, &mc_block, &rsp);
    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("t3t ndef format failed, ret=0x%X", ret);
        goto cleanup;
    }

    uint8_t *p_mc = rsp->data + T3T_RSP_OFFSET_BLCOK_DATA;
    if (p_mc[T3T_FELICALITE_OFFSET_SYS_OP] != T3T_DEFAULT_FELICALITE_SYS_OP) {
        // 当前卡片未开启NDEF支持，需要先开启NDEF支持，写入MC Block
        uint8_t mc[T3T_BLOCK_SIZE] = {0};
        if (!osi_memcpy_s(mc, T3T_BLOCK_SIZE, p_mc, T3T_BLOCK_SIZE)) {
            NFCLOG_E("t3t ndef format memcpy failed");
            ret = NCI_STATUS_EXT_COPY_FAILED;
            goto cleanup;
        }
        mc[T3T_FELICALITE_OFFSET_SYS_OP] = T3T_DEFAULT_FELICALITE_SYS_OP;
        mc[T3T_FELICALITE_OFFSET_RF_PRM] = T3T_DEFAULT_FELICALITE_RF_PRM;
        ret = t3t_update(T3T_SERVICE_CODE_NDEF_RW, T3T_BLOCK_ID_FELICALITE_MC, mc, &rsp);
        if (ret != NCI_STATUS_OK) {
            NFCLOG_E("t3t ndef format write mc, ret=0x%X", ret);
            goto cleanup;
        }
    }

    // 保存新的NDEF Attr Block
    if (!osi_memcpy_s(p_t3t->ndef_attr, T3T_BLOCK_SIZE, s_t3t_default_ndef_attr, T3T_BLOCK_SIZE)) {
        NFCLOG_E("t3t ndef format memcpy ndef attr failed");
        ret = NCI_STATUS_EXT_COPY_FAILED;
        goto cleanup;
    }
    set_ndef_info();

    // 写入NDEF Attr Block
    ret = t3t_update(T3T_SERVICE_CODE_NDEF_RW, 0, s_t3t_default_ndef_attr, &rsp);
    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("t3t ndef format write ndef attr failed, ret=0x%X", ret);
        goto cleanup;
    }
cleanup:
    free_nci_buf(rsp);
    return ret;
}

static tNCI_STATUS ndef_write(uint8_t *p_data, uint32_t data_len) {
    tT3T_INFO *p_t3t = &s_t3t_info;
    if (!p_t3t->is_ndef_detected) {
        NFCLOG_E("NDEF not detected");
        return NCI_STATUS_EXT_FAILED;
    }
    if (p_t3t->ndef_rw_flag == T3T_NDEF_READ_ONLY) {
        NFCLOG_E("Tag is read only");
        return NCI_STATUS_EXT_REJECTED;
    }
    uint16_t ndef_max_size = p_t3t->ndef_max_block * T3T_BLOCK_SIZE;
    if (data_len > ndef_max_size) {
        NFCLOG_E("Cannot write NDEF of size greather than %d bytes, NDEF data length=%d", ndef_max_size, data_len);
        return NCI_STATUS_EXT_REJECTED;
    }
    tNCI_STATUS ret = t3t_polling(T3T_SYSTEM_CODE_NDEF, T3T_POLL_RC_NO_SC, 0, false);
    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("poll ndef failed, ret=%d", ret);
        return ret;
    }

    // NDEF ATTR Block
    uint8_t ndef_attr[T3T_BLOCK_SIZE] = {
        T3T_NDEF_VERSION,
        p_t3t->ndef_nbr,
        p_t3t->ndef_nbw,
        (p_t3t->ndef_max_block >> 8) & 0xFF,
        p_t3t->ndef_max_block & 0xFF,
        0, 0, 0, 0, // RFU
        T3T_NDEF_WRITE_ON, // 设置写标志位为ON
        p_t3t->ndef_rw_flag,
        (p_t3t->ndef_len >> 16) & 0xFF,
        (p_t3t->ndef_len >> 8) & 0xFF,
        p_t3t->ndef_len & 0xFF,
        0, 0 // Checksum
    };
    // 计算校验和
    uint16_t sum = t3t_checksum(ndef_attr, 0, T3T_NDEF_ATTR_OFFSET_CHECKSUM);
    ndef_attr[T3T_NDEF_ATTR_OFFSET_CHECKSUM] = (uint8_t)(sum >> 8) & 0xFF;
    ndef_attr[T3T_NDEF_ATTR_OFFSET_CHECKSUM + 1] = (uint8_t)(sum & 0xFF);

    tNCI_BUF *rsp = NULL;
    // 更新NDEF Attr Block
    ret = t3t_update(T3T_SERVICE_CODE_NDEF_RW, 0, ndef_attr, &rsp);
    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("t3t ndef write attr failed, ret=%d", ret);
        goto cleanup;
    }

    if (!osi_memcpy_s(p_t3t->ndef_attr, T3T_BLOCK_SIZE, ndef_attr, T3T_BLOCK_SIZE)) {
        NFCLOG_E("t3t ndef write memcpy failed");
        ret = NCI_STATUS_EXT_COPY_FAILED;
        goto cleanup;
    }
    set_ndef_info();

    // 写入NDEF数据
    uint16_t write_len = 0;
    uint16_t block_no = 1;
    while (write_len < data_len) {
        uint16_t remain_len = data_len - write_len;
        if (remain_len < T3T_BLOCK_SIZE) {
            uint8_t write_buf[T3T_BLOCK_SIZE] = {0};
            if (!osi_memcpy_s(write_buf, T3T_BLOCK_SIZE, p_data + write_len, remain_len)) {
                NFCLOG_E("t3t ndef write memcpy failed");
                ret = NCI_STATUS_EXT_COPY_FAILED;
                goto update_ndef_attr;
            }
            ret = t3t_update(T3T_SERVICE_CODE_NDEF_RW, block_no, write_buf, &rsp);
        } else {
            ret = t3t_update(T3T_SERVICE_CODE_NDEF_RW, block_no, p_data + write_len, &rsp);
        }
        if (ret != NCI_STATUS_OK) {
            NFCLOG_E("t3t ndef write block failed, ret=%d", ret);
            goto update_ndef_attr;
        }
        write_len += T3T_BLOCK_SIZE;
        block_no++;
    }
    if (write_len < data_len) {
        NFCLOG_E("ndef write failed write_len=%d, data_len=%d", write_len, data_len);
        ret = NCI_STATUS_EXT_FAILED;
        goto update_ndef_attr;
    }
update_ndef_attr:
    // 设置WRITE_FLAG为OFF
    ndef_attr[T3T_NDEF_ATTR_OFFSET_WRITE_FLAG] = T3T_NDEF_WRITE_OFF;
    if (ret == NCI_STATUS_OK) {
        // 当NDEF写入成功时，更新长度为新的长度
        ndef_attr[T3T_NDEF_ATTR_OFFSET_LN] = (uint8_t)(data_len >> 16) & 0xFF;
        ndef_attr[T3T_NDEF_ATTR_OFFSET_LN + 1] = (uint8_t)(data_len >> 8) & 0xFF;
        ndef_attr[T3T_NDEF_ATTR_OFFSET_LN + 2] = (uint8_t)(data_len & 0xFF);
        p_t3t->ndef_len = data_len;
    }
    // 计算校验和
    sum = t3t_checksum(ndef_attr, 0, T3T_NDEF_ATTR_OFFSET_CHECKSUM);
    ndef_attr[T3T_NDEF_ATTR_OFFSET_CHECKSUM] = (uint8_t)(sum >> 8) & 0xFF;
    ndef_attr[T3T_NDEF_ATTR_OFFSET_CHECKSUM + 1] = (uint8_t)(sum & 0xFF);

    // 更新NDEF Attr Block
    ret = t3t_update(T3T_SERVICE_CODE_NDEF_RW, 0, ndef_attr, &rsp);
    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("t3t ndef update attr failed, ret=%d", ret);
        goto cleanup;
    }
    if (!osi_memcpy_s(p_t3t->ndef_attr, T3T_BLOCK_SIZE, ndef_attr, T3T_BLOCK_SIZE)) {
        NFCLOG_E("t3t ndef write memcpy failed");
        ret = NCI_STATUS_EXT_COPY_FAILED;
        goto cleanup;
    }
    set_ndef_info();
cleanup:
    free_nci_buf(rsp);
    return ret;
}

static tNCI_STATUS is_ndef_formatable() {
    return s_t3t_info.is_felica ? NCI_STATUS_OK : NCI_STATUS_EXT_NOT_SUPPORTED;
}

static tNCI_STATUS set_tag_read_only(bool is_hard_lock) {
    /**
     * 1. 检查NDEF detect状态
     * 2. 写NDEF Attr Block
     * 3. 写MC Block
     */
    tT3T_INFO *p_t3t = &s_t3t_info;
    if (!p_t3t->is_ndef_detected) {
        NFCLOG_E("NDEF not detected");
        return NCI_STATUS_EXT_FAILED;
    }
    if (p_t3t->ndef_rw_flag == T3T_NDEF_READ_ONLY) {
        NFCLOG_E("NDEF is already read only");
        return NCI_STATUS_OK;
    }
    tNCI_STATUS ret = NCI_STATUS_EXT_FAILED;
    tNCI_BUF *rsp = NULL;
    if (p_t3t->curr_system_code != T3T_SYSTEM_CODE_NDEF) {
        ret = t3t_polling(T3T_SYSTEM_CODE_FELICA_LITE, T3T_POLL_RC_NO_SC, 0, false);
        if (ret != NCI_STATUS_OK) {
            NFCLOG_E("t3t polling failed, ret=%d", ret);
            goto cleanup;
        }
    }
    p_t3t->ndef_attr[T3T_NDEF_ATTR_OFFSET_RW_FLAG] = T3T_NDEF_READ_ONLY;
    uint16_t sum = t3t_checksum(p_t3t->ndef_attr, 0, T3T_NDEF_ATTR_OFFSET_CHECKSUM);
    p_t3t->ndef_attr[T3T_NDEF_ATTR_OFFSET_CHECKSUM] = (uint8_t)(sum >> 8) & 0xFF;
    p_t3t->ndef_attr[T3T_NDEF_ATTR_OFFSET_CHECKSUM + 1] = (uint8_t)(sum & 0xFF);
    ret = t3t_update(T3T_SERVICE_CODE_NDEF_RW, 0, p_t3t->ndef_attr, &rsp);
    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("t3t ndef update attr failed, ret=%d", ret);
        goto cleanup;
    }
    if (!is_hard_lock) {
        // 软锁定不需要写MC Block
        goto cleanup;
    }

    uint16_t mc_block = T3T_BLOCK_ID_FELICALITE_MC;
    ret = t3t_check(T3T_SERVICE_CODE_NDEF_RO, 1, &mc_block, &rsp);
    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("t3t ndef check failed, ret=%d", ret);
        goto cleanup;
    }
    uint8_t *p_mc = rsp->data + T3T_RSP_OFFSET_BLCOK_DATA;
    if (p_mc[T3T_FELICALITE_OFFSET_SYS_OP] != T3T_DEFAULT_FELICALITE_SYS_OP) {
        NFCLOG_E("t3t felica sys op not match, 0x%02X", p_mc[T3T_FELICALITE_OFFSET_SYS_OP]);
        ret = NCI_STATUS_EXT_FAILED;
        goto cleanup;
    }
    uint8_t mc_block_data[T3T_BLOCK_SIZE] = {0};
    if (!osi_memcpy_s(mc_block_data, T3T_BLOCK_SIZE, p_mc, T3T_BLOCK_SIZE)) {
        NFCLOG_E("t3t memcpy mc data failed");
        ret = NCI_STATUS_EXT_COPY_FAILED;
        goto cleanup;
    }
    mc_block_data[T3T_FELICALITE_OFFSET_MC_SP] = 0x00;
    mc_block_data[T3T_FELICALITE_OFFSET_MC_SP + 1] = 0xC0;
    mc_block_data[T3T_FELICALITE_OFFSET_RF_PRM] = 0x07;

    ret = t3t_update(T3T_SERVICE_CODE_NDEF_RW, T3T_BLOCK_ID_FELICALITE_MC, mc_block_data, &rsp);
    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("t3t ndef update mc failed, ret=%d", ret);
        goto cleanup;
    }

cleanup:
    free_nci_buf(rsp);
    set_ndef_info();
    return ret;
}

#endif // IS_FEATURE_ON(NCI_FEATURE_RW_NDEF)

static tNCI_STATUS on_connect(tNCI_RW_TAG *p_tag) {
    if (!osi_memcpy_s(s_t3t_info.uid, T3T_UID_LEN, p_tag->uid, T3T_UID_LEN)) {
        NFCLOG_E("t3t uid copy failed");
        return NCI_STATUS_EXT_COPY_FAILED;
    }
    if (g_dta_mode_enabled) {
        NFCLOG_I("DTA mode enabled, skip get system code");
        return NCI_STATUS_OK;
    }

    tNCI_RF_SENSF_REQ_PARAMS sensf_req = T3T_SYSTEM_CODE_CHECK_PRESENCE << 16 | T3T_POLL_RC_SC << 8 | 0x0F;
    tNCI_RF_SENSF_RES sensf_res = {0};
    uint8_t res_count = 1;
    tNCI_STATUS ret = rf_t3t_polling(sensf_req, &sensf_res, &res_count);
    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("t3t polling failed, ret=%d", ret);
        return ret;
    }
    if (res_count == 0 || sensf_res.length != NCI_RF_SENSF_RES_MAX_LENGTH) {
        NFCLOG_E("t3t polling failed, res_count=%d, sensf_res.length=%d", res_count, sensf_res.length);
        return NCI_STATUS_EXT_FAILED;
    }
    tNCI_RW_POLL_DATA *p_poll_data = &p_tag->poll_data[p_tag->index];
    if (!osi_memcpy_s(p_poll_data->data, NCI_RW_MAX_POLL_DATA_LEN, &sensf_res.res[T3T_SENSF_RES_PMM_OFFSET], NCI_RF_SENSF_RES_MAX_LENGTH-T3T_SENSF_RES_PMM_OFFSET)) {
        NFCLOG_E("t3t memcpy failed");
        return NCI_STATUS_EXT_COPY_FAILED;
    }
    p_poll_data->len = NCI_RF_SENSF_RES_MAX_LENGTH - T3T_SENSF_RES_PMM_OFFSET;
    uint16_t system_code = (sensf_res.res[T3T_SENSF_RES_RD_OFFSET] << 8) | sensf_res.res[T3T_SENSF_RES_RD_OFFSET + 1];
    NFCLOG_I("t3t system code: 0x%04X", system_code);
    s_t3t_info.is_felica = (system_code == T3T_SYSTEM_CODE_FELICA_LITE);
    return NCI_STATUS_OK;
}

static tNCI_STATUS on_disconnect() {
    osi_memset_s(&s_t3t_info, sizeof(tT3T_INFO), 0, sizeof(tT3T_INFO));
    return NCI_STATUS_OK;
}

static tNCI_STATUS presence_check() {
    return t3t_polling(T3T_SYSTEM_CODE_CHECK_PRESENCE, T3T_POLL_RC_SC, T3T_TSN_CHECK_PRESENCE, true);
}

static tNCI_STATUS check_transceive_resp(uint8_t *p_rsp, uint16_t *p_rsp_len) {
    if (!p_rsp || !p_rsp_len || *p_rsp_len < 1) {
        NFCLOG_E("invalid param");
        return NCI_STATUS_EXT_INVALID_PARAM;
    }
    uint16_t rsp_len = *p_rsp_len;
    if (p_rsp[rsp_len - 1] != 0x00) {
        NFCLOG_E("t3t transceive failed, status=0x%02X", p_rsp[rsp_len - 1]);
        return NCI_STATUS_EXT_FAILED;
    }
    *p_rsp_len = rsp_len - 1; // 去掉最后一个状态字
    return NCI_STATUS_OK;
}

tNCI_RW_TAG_API g_rw_t3t_api = {
    .max_retry_count = NCI_RW_DEFAULT_MAX_RETRY_COUNT,
    .on_connect = on_connect,
    .on_disconnect = on_disconnect,
    .presence_check = presence_check,
    .check_transceive_resp = check_transceive_resp,
#if IS_FEATURE_ON(NCI_FEATURE_RW_NDEF)
    .ndef_detect = ndef_detect,
    .ndef_read = ndef_read,
    .ndef_format = ndef_format,
    .ndef_write = ndef_write,
    .is_ndef_formatable = is_ndef_formatable,
    .set_tag_read_only = set_tag_read_only,
#endif // IS_FEATURE_ON(NCI_FEATURE_RW_NDEF)
};

#endif // IS_FEATURE_ON(NCI_FEATURE_RW_T3T)

